package feevale.boteco.bean;

import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;

import feevale.boteco.util.Agente;
import feevale.boteco.view.table.CervejaTableModel;
import feevale.boteco.view.table.ClienteTableModel;

@SuppressWarnings("serial")
public class Geladeira extends JPanel implements Runnable {
	
	private Boteco boteco;
	
	private Thread thread;
	
	private Integer id;
	
	private TipoCerveja tipoCerveja;
	private Queue<Cerveja> cervejas;
	private Queue<Cliente> clientesEspera;
	
	private Garcon garcon;
	
	private ClienteTableModel clienteTableModel;
	private JTable tblClientes;
	
	private CervejaTableModel cervejaTableModel;
	private JTable tblCervejas;
	
	private JLabel lblSituacao;
	private JTextField txQuantidade;
	private JLabel lblGarconGeladeira;
	private JTextField txTempoBuscaCliente;
	
	private Integer idx;
	
	public Geladeira(Integer id, Boteco boteco) {
		this.id = id;
		this.boteco = boteco;
		this.tipoCerveja = boteco.getTipoCeva(id);
		
		setLayout(null);
		
		setup();
		
		initLayout();
	}
	
	/**
	 * Configurações iniciais.
	 */
	private void setup() {
		this.cervejas = new LinkedList<Cerveja>();
		this.clientesEspera = new LinkedList<Cliente>();
		
		encher();
		
		this.thread = new Thread(this);
		thread.start();
	}
	
	private void initLayout() {
		
		setBorder(BorderFactory.createTitledBorder("Geladeira - " + tipoCerveja.getNome()));
		
		lblSituacao = new JLabel();
		lblSituacao.setBounds(10, 20, 260, 20);
		add(lblSituacao);
		
		JLabel lblQuantidade = new JLabel("Quantidade:");
		lblQuantidade.setBounds(10, 50, 95, 20);
		add(lblQuantidade);
		
		txQuantidade = new JTextField(Boteco.DEFAULT_CAPACIDADE_MAXIMA.toString());
		txQuantidade.setEditable(false);
		txQuantidade.setBounds(105, 50, 60, 20);
		add(txQuantidade);
		
		JLabel lblTempoBusca = new JLabel("Tempo:");
		lblTempoBusca.setBounds(175, 50, 55, 20);
		add(lblTempoBusca);
		
		txTempoBuscaCliente = new JTextField();
		txTempoBuscaCliente.setEditable(false);
		txTempoBuscaCliente.setBounds(235, 50, 40, 20);
		add(txTempoBuscaCliente);
		
		// cervejas
		
		cervejaTableModel = new CervejaTableModel((List<Cerveja>) this.cervejas);
		tblCervejas = new JTable(cervejaTableModel);
		
		JPanel pnlCervejas = new JPanel();
		pnlCervejas.setLayout(null);
		pnlCervejas.setBounds(5, 80, 165, 380);
		
		JScrollPane scpCervejas = new JScrollPane(tblCervejas);
		scpCervejas.setBounds(0, 0, 165, 380);
		pnlCervejas.add(scpCervejas);
		
		add(pnlCervejas);
		
		// clientes
		
		clienteTableModel = new ClienteTableModel((List<Cliente>) clientesEspera);
		tblClientes = new JTable(clienteTableModel);
		
		JPanel pnlClientes = new JPanel();
		pnlClientes.setLayout(null);
		pnlClientes.setBounds(175, 80, 100, 380);
		
		JScrollPane scpClientes = new JScrollPane(tblClientes);
		scpClientes.setBounds(0, 0, 100, 380);
		pnlClientes.add(scpClientes);
		
		add(pnlClientes);
		
		JLabel lblGarcon = new JLabel("Garçon:");
		lblGarcon.setBounds(10, 470, 95, 20);
		add(lblGarcon);
		
		lblGarconGeladeira = new JLabel();
		lblGarconGeladeira.setBounds(105, 470, 150, 20);
		add(lblGarconGeladeira);
		
	}
	
	/**
	 * Enche a geladeira
	 */
	private void encher() {
		for (idx = 1; idx <= Boteco.DEFAULT_CAPACIDADE_MAXIMA; idx++) {
			Cerveja cerveja = new Cerveja();
			cerveja.setId(idx);
			cerveja.setTipoCerveja(tipoCerveja);
			cervejas.offer(cerveja);
		}
	}
	
	/**
	 * Quando chegar no nível mínimo de cervejas, chama o próximo garçon disponível no boteco para abastecer.
	 */
	@Override
	public void run() {
		
		while (true) {
			try {
				Thread.sleep(100);
				
				if (cervejas.size() <= Boteco.DEFAULT_CAPACIDADE_MINIMA && this.garcon == null && !(Boteco.GARCONS.isEmpty())) {
					Garcon garcon = boteco.chamaGarcon();
					garcon.setGeladeira(this);
					
					setGarcon(garcon);
				}
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void abrirPorta(Agente agente) {
		synchronized(this) {
			agente.abreGeladeira(this);
		}
		
		agente.fechaGeladeira(this);
	}

	/**
	 * Atualia a situação da geladeira de acordo com o agente que está manipulando-a
	 * @param situacao
	 */
	public void atualizaSituacao(String situacao) {
		this.lblSituacao.setText(situacao);
	}
	
	/**
	 * Atualiza a tabela de clientes esperando para pegar uma ceva.
	 */
	public void atualizaTableClientes() {
		this.clienteTableModel.fireTableDataChanged();
	}
	
	/**
	 * Atualiza tabela que representa a geladeira.
	 */
	public void atualizaTableCervejas() {
		this.cervejaTableModel.fireTableDataChanged();
		this.txQuantidade.setText(String.valueOf(getCervejas().size()));
	}
	
	/**
	 * Retorna o garçon associado à geladeira.
	 * @return
	 */
	public Garcon getGarcon() {
		return this.garcon;
	}
	
	/**
	 * Atribui um garçon do boteco à geladeira.
	 * @param garcon
	 */
	public void setGarcon(Garcon garcon) {
		this.garcon = garcon;
		atualizaGarconGeladeira();
	}
	
	/**
	 * Dispensa o garçon.
	 */
	public void removeGarcon() {
		setGarcon(null);
	}
	
	/**
	 * Atualiza o dado referente ao garçon que abastecerá a geladeira.
	 */
	public void atualizaGarconGeladeira() {
		this.lblGarconGeladeira.setText(this.garcon != null ? this.garcon.getNome() : "");
	}
	
	/**
	 * Atualiza o tempo de busca de uma cerveja para cada cliente. 
	 * @param tempo
	 */
	public void atualizaTempoAgente(Double tempo) {
		this.txTempoBuscaCliente.setText(tempo != null ? new DecimalFormat("0.00").format(tempo) : "");
	}
	
	public Integer getId() {
		return id;
	}
	
	public Boteco getBoteco() {
		return boteco;
	}
	
	public Queue<Cliente> getClientesEspera() {
		return clientesEspera;
	}

	public Queue<Cerveja> getCervejas() {
		return cervejas;
	}
	
	public Integer getIdx() {
		return idx;
	}
	
	public void incrementIdx() {
		this.idx++;
	}
	
	public TipoCerveja getTipoCerveja() {
		return tipoCerveja;
	}

}
